﻿/*
 * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
 *
 * This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
 *
 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
 */

#ifndef ZLMEDIAKIT_MEDIASOURCE_H
#define ZLMEDIAKIT_MEDIASOURCE_H

#include <mutex>
#include <string>
#include <memory>
#include "Util/TimeTicker.h"
#include "Util/List.h"

using namespace std;


namespace toolkit {

	/**
	 * 解析url获取媒体相关信息
	 */
	class MediaInfo {
	public:
		~MediaInfo() {}
		MediaInfo() {}
		MediaInfo(const string &url) { parse(url); }
		void parse(const string &url);

	public:
		string _full_url;
		string _schema;
		string _host;
		string _port;
		string _vhost;
		string _app;
		string _streamid;
		string _param_strs;
	};

	class BytesSpeed {
	public:
		BytesSpeed() = default;
		~BytesSpeed() = default;

		/**
		 * 添加统计字节
		 */
		BytesSpeed& operator += (size_t bytes) {
			_bytes += bytes;
			if (_bytes > 1024 * 1024) {
				//数据大于1MB就计算一次网速
				computeSpeed();
			}
			return *this;
		}

		/**
		 * 获取速度，单位bytes/s
		 */
		int getSpeed() {
			if (_ticker.elapsedTime() < 1000) {
				//获取频率小于1秒，那么返回上次计算结果
				return _speed;
			}
			return computeSpeed();
		}

	private:
		int computeSpeed() {
			auto elapsed = _ticker.elapsedTime();
			if (!elapsed) {
				return _speed;
			}
			_speed = (int)(_bytes * 1000 / elapsed);
			_ticker.resetTime();
			_bytes = 0;
			return _speed;
		}

	private:
		int _speed = 0;
		size_t _bytes = 0;
		Ticker _ticker;
	};

	///缓存刷新策略类
	class FlushPolicy {
	public:
		FlushPolicy() = default;
		~FlushPolicy() = default;

		bool isFlushAble(bool is_video, bool is_key, uint64_t new_stamp, size_t cache_size);

	private:
		uint64_t _last_stamp[2] = { 0, 0 };
	};

	/// 合并写缓存模板
	/// \tparam packet 包类型
	/// \tparam policy 刷新缓存策略
	/// \tparam packet_list 包缓存类型
	template<typename packet, typename policy = FlushPolicy, typename packet_list = List<std::shared_ptr<packet> > >
	class PacketCache {
	public:
		PacketCache() {
			_cache = std::make_shared<packet_list>();
		}

		virtual ~PacketCache() = default;

		void inputPacket(uint64_t stamp, bool is_video, std::shared_ptr<packet> pkt, bool key_pos) {
			if (_policy.isFlushAble(is_video, key_pos, stamp, _cache->size())) {
				flushAll();
			}

			//追加数据到最后
			_cache->emplace_back(std::move(pkt));
			if (key_pos) {
				_key_pos = key_pos;
			}
		}

		virtual void clearCache() {
			_cache->clear();
		}

		virtual void onFlush(std::shared_ptr<packet_list>, bool key_pos) = 0;

	private:
		void flushAll() {
			if (_cache->empty()) {
				return;
			}
			onFlush(std::move(_cache), _key_pos);
			_cache = std::make_shared<packet_list>();
			_key_pos = false;
		}

	private:
		bool _key_pos = false;
		policy _policy;
		std::shared_ptr<packet_list> _cache;
	};

} /* namespace toolkit */
#endif //ZLMEDIAKIT_MEDIASOURCE_H